#include "window_handler_win32.h"
#ifdef _PLATFORM_WIN32
#include "gameflow/game_flow_manager.h"
#include "gameflow/ui_popup.h"
#include "ui/ui_manager.h"
#include "graphics/graphics.h"
#include "graphics/graphics_util.h"
#include "audio/audio.h"
#include "input/mouse.h"
#include "input/keyboard.h"
#include "console/console.h"
#include "font/font_manager.h"
#include "util/timer.h"		    // Needs to come in early
#include "util/mmgr.h"		    // Needs to come in early
#include "util/common_macros.h"		// macros
#include "util/log.h"		    // logging


#include <Shlobj.h>
#include <cassert>
#include <Windowsx.h>
#include <Winuser.h>

#ifdef _ENABLE_DX8
#include "dx8graphics/dx8_graphics.h"
extern void		SLEIPNER_CREATE_DX8();
#endif //_ENABLE_DX8


using namespace util;

static void PopupLastError ( )
{
    LPVOID lpMsgBuf;

    char errmsg[32];

    if ( !FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | 
                            FORMAT_MESSAGE_FROM_SYSTEM | 
                            FORMAT_MESSAGE_IGNORE_INSERTS,
                            NULL,
                            GetLastError ( ) ,
                            MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
                            ( LPTSTR ) &lpMsgBuf,
                            0,
                            NULL ) )
        return;

    sprintf ( errmsg, "Windows Error: %d", GetLastError ( ) );
	_LOG(MSG_ERROR, errmsg);

    // Display the string.
    MessageBox ( NULL, ( LPCTSTR ) lpMsgBuf, errmsg, MB_OK | MB_ICONINFORMATION );

    // Free the buffer.
    LocalFree( lpMsgBuf );
}


bool	WindowHandlerWin32::GetCurrentResolution(unsigned int& Width, unsigned int& Height, unsigned int &Depth)
{
	DEVMODE device_mode;
	memset(&device_mode, 0, sizeof(DEVMODE));
	device_mode.dmSize = sizeof(DEVMODE);
	EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &device_mode);

	Width = device_mode.dmPelsWidth;
	Height = device_mode.dmPelsHeight;
	Depth = device_mode.dmBitsPerPel;
	return true;
}

bool	WindowHandlerWin32::SetResolution(unsigned int Width, unsigned int Height, unsigned int Depth)
{
	unsigned int ScreenX = GetSystemMetrics(SM_CXSCREEN); //get current resolution X
	unsigned int ScreenY = GetSystemMetrics(SM_CYSCREEN); //get current resolution Y	
	if (ScreenX == Width && ScreenY == Height)
		return true;

	DEVMODE device_mode;
	memset(&device_mode, 0, sizeof(DEVMODE));

	device_mode.dmSize = sizeof(DEVMODE);

	device_mode.dmPelsWidth  = Width;
	device_mode.dmPelsHeight = Height;
	device_mode.dmBitsPerPel = Depth;
	device_mode.dmFields     = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL;

	long Res = ChangeDisplaySettings(&device_mode, CDS_FULLSCREEN);
	if (Res == DISP_CHANGE_SUCCESSFUL)
	{
		_LOG(MSG_COMMENT, "Successfully switched desktop resolution to " << Width << " x " << Height);
		m_ResolutionChanged = (Width != m_OrigWidth) || (Height != m_OrigHeight) || (Depth != m_OrigDepth);
		return true;
	}
	else
	{
		_LOG(MSG_WARNING, "Failed to change desktop resolution");
		return false;
	}
}

bool	WindowHandlerWin32::RestoreResolution()
{
	return SetResolution(m_OrigWidth, m_OrigHeight, m_OrigDepth);
}

bool	WindowHandlerWin32::DetectWidescreenMode()
{
	DEVMODE device_mode;
	memset(&device_mode, 0, sizeof(DEVMODE));
	device_mode.dmSize = sizeof(DEVMODE);
	EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &device_mode);

	m_OrigWidth		= device_mode.dmPelsWidth;
	m_OrigHeight	= device_mode.dmPelsHeight;
	m_OrigDepth		= device_mode.dmBitsPerPel;

	float	Ratio	= float(m_OrigWidth)/float(m_OrigHeight);
	bool Widescreen = (Ratio > 1.5f) && (m_OrigWidth > 800);	// if they're running less than 800 resolution, just force it to 800x600
	if (Widescreen)
		_LOG(MSG_COMMENT,"Wide screen Detected !");
	else
		_LOG(MSG_COMMENT,"Regular screen Detected !");
	return Widescreen;
}

WindowHandlerWin32*	WindowHandlerWin32::pSelf = NULL;


WindowHandlerWin32::WindowHandlerWin32(HINSTANCE	hInst) :
	WindowHandler(),
	m_Instance(hInst),
	m_Style(0),
	m_ExtendedStyle(0),
	m_hwnd(NULL),
	m_MouseTrackingSet(false)
{
	pSelf = this;
	m_IsWidescreen = DetectWidescreenMode();
}

WindowHandlerWin32::~WindowHandlerWin32()
{
	pSelf = NULL;
}
bool		WindowHandlerWin32::InitWindow(const std::string& Name, const std::string& Title, int	X, int Y, int Width, int Height) 
{
	m_Title = Title;
	m_AppName = Name;
	_LOG(MSG_COMMENT, "Starting up application " << Name);


    HWND originalHwnd = ::FindWindow(m_AppName.c_str(), 0);
	if (originalHwnd)
	{
		_LOG(MSG_FATAL, "Already one instance of game running!");
        ::SetForegroundWindow ( originalHwnd );
        if ( ::IsIconic ( originalHwnd ) ) ::ShowWindow ( originalHwnd, SW_RESTORE );
		return false;
	}
	
	// Create the class definition
    m_Class.cbSize			= sizeof ( WNDCLASSEX );
    m_Class.style			= 0;
    m_Class.lpszClassName	= m_AppName.c_str ( );
    m_Class.hInstance		= m_Instance;
    m_Class.hIcon			= GetApplicationIcon();
    m_Class.hIconSm			= GetApplicationIconSm();
    m_Class.lpszMenuName	= 0;
    m_Class.cbClsExtra		= 0;
    m_Class.cbWndExtra		= 0;
    m_Class.hbrBackground	= reinterpret_cast<HBRUSH> ( COLOR_WINDOW + 1 );
    m_Class.hCursor			= NULL; 
	m_Class.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
    m_Class.lpfnWndProc		= defWndProc;

	if (!::RegisterClassEx ( &m_Class ))
	{
		_LOG(MSG_FATAL, "Unable to create class!");
		PopupLastError();
		return false;
	}

	// setup styles
    m_ExtendedStyle	= 0;
	m_Style = WS_CLIPCHILDREN | WS_POPUP | WS_BORDER | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX;

	// Setup window size
	unsigned int	ScreenD;
	unsigned int Caption = GetSystemMetrics(SM_CYCAPTION);
	unsigned int BorderX = GetSystemMetrics(SM_CXBORDER);
	unsigned int BorderY = GetSystemMetrics(SM_CYBORDER);
	unsigned int ScreenX = GetSystemMetrics(SM_CXSCREEN); //get current resolution X
	unsigned int ScreenY = GetSystemMetrics(SM_CYSCREEN); //get current resolution Y
	unsigned int DialogX = GetSystemMetrics(SM_CXDLGFRAME);
	unsigned int DialogY = GetSystemMetrics(SM_CYDLGFRAME);
	GetCurrentResolution(m_OrigWidth, m_OrigHeight, ScreenD);

	m_hwnd		 = 0;
    m_x			 = (m_OrigWidth -Width)/2;	
    m_y			 = (m_OrigHeight -Height)/2;			
    m_BaseWidth = m_Width = Width;
    m_BaseHeight = m_Height = Height;	
    m_hWndParent = 0;				
    m_hMenu		 = 0;				
	GraphicsUtil::SetWindowSize(Width, Height);

	// create the window
	m_WindowRect.left		= int( m_x );
	m_WindowRect.right		= int( m_x + m_Width + (BorderX*2) + (DialogX*2));
	m_WindowRect.top		= int ( m_y );
	m_WindowRect.bottom		= int( m_y + m_Height + (BorderY*2) + Caption + (DialogY*2));

    m_hwnd = ::CreateWindowEx ( m_ExtendedStyle,
							    m_AppName.c_str ( ),
							    m_Title.c_str ( ),
							    m_Style,
							    m_WindowRect.left,
							    m_WindowRect.top,
								m_WindowRect.right - m_WindowRect.left,	// Calculate Window Width,
							    m_WindowRect.bottom - m_WindowRect.top,		// Calculate Window Height,
							    m_hWndParent,
							    m_hMenu,
							    m_Instance,
							    this );
	if ( m_hwnd == 0 )
    {
		_LOG(MSG_FATAL, "Unable to create window!");
        PopupLastError( );
        return false;
    }
	::UpdateWindow ( m_hwnd );
	::SetCursor(::LoadCursor( 0, IDC_ARROW ));

    RecalcWindowSize();
	return true;
}
bool	WindowHandlerWin32::InitGraphics()
{
#ifdef _ENABLE_DX8
	// let's try the DX8 codepath instead?
	SLEIPNER_CREATE_DX8();
	GetDXGraphics()->SetHWND(m_hwnd);
	if (!GetGraphics()->Init())
	{
		MessageBox(m_hwnd, 
			"Unable to initialize graphics. Is DX8 installed? If it's not, you can download the latest from http://download.microsoft.com", 
			"Failed to init graphics. Exiting", S_OK);
		return false;
	}
	_LOG(MSG_ERROR, "DX8 initialized ok!");
#endif //_ENABLE_DX8

	return true;
}

void	WindowHandlerWin32::RecalcWindowSize()
{
	if (IsFullscreen())
	{
		m_WindowRect.left = m_WindowRect.top = 0;
		m_WindowRect.right = GetSystemMetrics(SM_CXSCREEN);
		m_WindowRect.bottom = GetSystemMetrics(SM_CYSCREEN);
	} else
	{
		unsigned int Caption = GetSystemMetrics(SM_CYCAPTION);
		unsigned int BorderX = GetSystemMetrics(SM_CXBORDER);
		unsigned int BorderY = GetSystemMetrics(SM_CYBORDER);
		unsigned int ScreenX = GetSystemMetrics(SM_CXSCREEN); //get current resolution X
		unsigned int ScreenY = GetSystemMetrics(SM_CYSCREEN); //get current resolution Y

		RECT    WindowSize;
		GetWindowRect(m_hwnd, &WindowSize);

		m_WindowRect.left	 = WindowSize.left + BorderX;
		m_WindowRect.right	 = WindowSize.right - BorderX;
		m_WindowRect.top	 = WindowSize.top + Caption + BorderY;
		m_WindowRect.bottom = WindowSize.bottom - BorderY; 

	}	
	m_x = m_WindowRect.left;
	m_y = m_WindowRect.top;
}


bool		WindowHandlerWin32::DestroyWindow() 
{
	pSelf = NULL;
	m_IsPaused = true;
	m_IsDestroyed = true;
	return true;
}
bool		WindowHandlerWin32::Tick(float dt)
{
    MSG  msg;
	//if ( ::PeekMessage ( &msg, NULL, 0,0, PM_REMOVE ) ) // Is There A Message Waiting?
	while ( ::PeekMessage ( &msg, NULL, 0,0, PM_REMOVE ) ) // ADRIAN: process all my msgs at each tick? // UPDATE: YES! fixes minimize/restore issues
	{
		WndProc ( m_hwnd, msg.message,  msg.wParam, msg.lParam );
	}
	return true;
}
	
bool		WindowHandlerWin32::Minimize()
{
    //ShowWindow(m_hwnd, SW_HIDE);
	// ADRIAN: shouldn't it be minimize and not hide?
	ShowWindow(m_hwnd, SW_MINIMIZE);
	return true;
}
bool		WindowHandlerWin32::Maximize()
{
    ShowWindow(m_hwnd, SW_SHOW);
	return true;
}

void		WindowHandlerWin32::SwitchFullscreen(int Width, int Height)
{
	// determine if we're on a widescreen 
	if (IsWidescreen())
	{
		unsigned int w,h;
		GetGraphics()->GetBestWideScreenRes(w,h);//add false to get a bugged bordered unstretched screen
		SetWidth(w);
		SetHeight(h);
	}
	int tempScreenWidth = ScreenWidth();
	int tempScreenHeight = ScreenHeight();
	Graphics::s_PixelOffsetX = (GetWidth() - ScreenWidth()) / 2;
	Graphics::s_PixelOffsetY = (GetHeight() - ScreenHeight()) / 2;
	GetGraphics()->SetOriginalPixelOffset(Graphics::s_PixelOffsetX, Graphics::s_PixelOffsetY);

	m_IsFullscreen = true;
	m_Style = GetWindowLong(m_hwnd, GWL_STYLE);
	m_ExtendedStyle = GetWindowLong(m_hwnd, GWL_EXSTYLE);

	ShowWindow(m_hwnd, SW_HIDE);
	ResetDevice();
	ShowWindow(m_hwnd, SW_SHOW);
}

void		WindowHandlerWin32::SwitchWindowed(int Width, int Height)
{
	Width = ScreenWidth();
	Height = ScreenHeight();
	Graphics::s_PixelOffsetX = 0;
	Graphics::s_PixelOffsetY = 0;
	m_Width = Width;
	m_Height = Height;

	m_IsFullscreen = false;

	ShowWindow(m_hwnd, SW_HIDE);
	ResetDevice();
	ShowWindow(m_hwnd, SW_SHOW);
}


void		WindowHandlerWin32::ResetDevice()
{
	FontManager::Instance().Flush();
	ui::UIManager::Instance().ShutdownFlash();
	GetGraphics()->Flush();
//	res::ResMan::Instance().ReleaseAll();		// flush all resources?

	if (GetGraphics()->ResetWindow(m_Width, m_Height, m_IsFullscreen))
	{
	//	res::ResMan::Instance().ReinitAll();
		ui::UIManager::Instance().ResetResources();
		FontManager::Instance().Recreate();
	} else
	{
		
	}
}

bool		WindowHandlerWin32::UpdateOS()
{
	// let the message pump go
	if (HasFocus())
	{
		// give a little back to the OS
		Sleep(1);
		m_IsPaused = false;
	} else
	{
		Sleep(100);
		m_IsPaused = true;
	}
	return true;
}

bool		WindowHandlerWin32::OnGainFocus()
{
	gameflow::GameFlowManager&	GM = gameflow::GameFlowManager::Instance();
	gameflow::GameState* pState = GM.GetCurrentState();
	AUDIO().RestartAll();
	if (pState) pState->GainFocus();
	return true;
}

bool		WindowHandlerWin32::OnLooseFocus()
{
	gameflow::GameFlowManager&	GM = gameflow::GameFlowManager::Instance();
	gameflow::GameState* pState = GM.GetCurrentState();
	AUDIO().PauseAll();
	if (pState) pState->LoseFocus();


	// if this is a fullscreen/widescreen and we had to change the resolution to do so
	// restore it and be nice.
/*	if (g_bWidescreen && m_IsFullscreen && !g_bNativeWidescreen && g_DesktopResChanged)
	{
		// ADRIAN: simulate a fullscreen switch
		ShowWindow(m_hwnd, SW_MINIMIZE);
		RestoreDisplayRes();
	}*/
	if (IsWidescreen() && IsFullscreen() && !IsNativeWidescreen() && IsResolutionChanged())
	{
		_LOG(MSG_COMMENT, "Resolution was changed. Restoring...");
		ShowWindow(m_hwnd, SW_MINIMIZE);
		RestoreResolution();
	}
	return true;
}

HICON	WindowHandlerWin32::InitIcon( const std::string& Name)
{
	HICON hIcon = (HICON)LoadImageA(m_Instance, Name.c_str(), IMAGE_ICON, 0, 0, LR_DEFAULTSIZE | LR_LOADTRANSPARENT);
	DWORD Res = SetClassLong(m_hwnd,          // window Handle
							 GCL_HICON,     // index of the Icon field
								(LONG)hIcon); // the icon handler

	return hIcon;
}

bool		WindowHandlerWin32::SetCursor(const std::string& File)
{
	CursorData*	pData = m_CursorData.GetElement(File);
	if (!pData)
	{
		pData = new CursorData;
		pData->Name = File;
		pData->Cursor = InitCursor(File);
		m_CursorData.AddElement(File, pData);
	}
	::SetCursor(pData->Cursor);
	return true;
}

math::Vec2	WindowHandlerWin32::MapPointToPos(int x, int y)
{
	math::Vec2 Point;
	RecalcWindowSize();	// needed?

	unsigned int ScreenX = GetSystemMetrics(SM_CXSCREEN); //get current resolution X
	unsigned int ScreenY = GetSystemMetrics(SM_CYSCREEN); //get current resolution Y

	LONG wndWidth = m_WindowRect.right-m_WindowRect.left;
	LONG wndHeight = m_WindowRect.bottom-m_WindowRect.top;
	LONG offsetX = 0;
	LONG offsetY = 0;

	Point.x = (float)x / (float)wndWidth;
	Point.y = (float)y / (float)wndHeight;
	if (Graphics::s_PixelOffsetX || Graphics::s_PixelOffsetY)
	{
		float dx = (float)Graphics::s_PixelOffsetX / (float)m_Width;
		float dy = (float)Graphics::s_PixelOffsetY / (float)m_Height;
		Point.x = (Point.x - dx) / (1.0f - (2.0f * dx));
		Point.y = (Point.y - dy) / (1.0f - (2.0f * dy));
	}

	return Point;
}

HICON	WindowHandlerWin32::InitIcon( long	IconID )
{
	HICON hIcon = LoadIcon(m_Instance,  MAKEINTRESOURCE(IconID));
    DWORD Res = SetClassLong(m_hwnd,          // window Handle
							 GCL_HICON,     // index of the Icon field
							(LONG)hIcon); // the icon handler
	return hIcon;
}

HCURSOR		WindowHandlerWin32::InitCursor( const std::string& Name)
{
	HCURSOR hImage = LoadCursorFromFile (Name.c_str());
	return (HCURSOR)hImage;
}
std::string	WindowHandlerWin32::GetSaveFolder()
{
	char	Buffer[MAX_PATH];
	memset(Buffer, 0, sizeof(Buffer));
	bool Res  = SHGetSpecialFolderPathA(NULL, Buffer, CSIDL_APPDATA, 1)  >0;
	if (!Res)
	{
		return "";
	}
	char	FinalPath[MAX_PATH];
	sprintf(FinalPath, "%s/2dstar/", Buffer);
	int	Result = CreateDirectory(FinalPath, NULL);
	if (Res == 0)
	{
		// problem creating the file.. possibly because the file already exists?
	}

	return FinalPath;
}

void DELEGATE_CALL	WindowHandlerWin32::OnHardQuit(ui::UIWidget::WIDGET_EVENT Event, ui::UIWidget* pWidget)
{
	DestroyWindow();	
}

// hack; we don't want to drag in all the winnt nonsense.
#ifndef WM_MOUSEWHEEL
	#define WM_MOUSEWHEEL                   0x020A
#endif //WM_MOUSEWHEEL
LRESULT	WindowHandlerWin32::WndProc ( HWND _hwnd, UINT _msg, WPARAM _wparam, LPARAM _lparam )
{
	switch( _msg )
	{
/////////////////////////////////////////////////////////////////////////
// Window management
		case WM_CREATE:
			// what needs initializing here?
		break;
		case WM_CLOSE:
#ifdef _NOLOCALIZATION_
			if (!gameflow::UIPopupManager::Instance().StartYesNo(QUIT_YESNO, UI_DELEGATE(WindowHandlerWin32, OnHardQuit), NULL))
#else
			if (!gameflow::UIPopupManager::Instance().StartYesNo("QUIT_YESNO", UI_DELEGATE(WindowHandlerWin32, OnHardQuit), NULL))
#endif
			{
				DestroyWindow();	
			}
			return 0;
			break;
		case WM_SIZE:				
			// resized. 
			if (_wparam > 0 && _lparam > 0)
			{
				/*_LOG(MSG_WARNING, "WM_SIZE");
				switch (_wparam)
				{
				case SIZE_MAXHIDE: //Message is sent to all pop-up windows when some other window is maximized.
				case SIZE_MAXIMIZED: //The window has been maximized.
				case SIZE_MAXSHOW: //Message is sent to all pop-up windows when some other window has been restored to its former size.
				case SIZE_MINIMIZED: //The window has been minimized.
				case SIZE_RESTORED: //The window has been resized, but neither the SIZE_MINIMIZED nor SIZE_MAXIMIZED value applies.
					break;
				}
				*/

				if (_hwnd != m_hwnd) break; // doesn't concern us
				if (SIZE_MAXIMIZED == _wparam)
				{
					// ADRIAN: our game cannot be maximized!
					return 0;
					//_wparam = SIZE_RESTORED;
					//break;
				}
				else if ( (SIZE_MAXHIDE == _wparam) ||
						  (SIZE_MAXSHOW == _wparam) )
				{
					// we don't need to process these
					break;
				}

				GetGraphics()->Resize((unsigned int)LOWORD(_lparam), (unsigned int)HIWORD(_lparam));
			}
			break;
		case WM_ACTIVATE:
			{
				WORD ActState = LOWORD(_wparam);
				bool IsMinimized = HIWORD(_wparam) ? true : false; // this is the current state of the window, not a command to minimize or show
				//_LOG(MSG_WARNING, "WM_ACTIVATE " << ActState << (IsMinimized ? " minimized" : " not minimized"));

				if (!IsMinimized && (ActState==WA_ACTIVE || ActState==WA_CLICKACTIVE))
				{
					_LOG(MSG_WARNING, "GAINED FOCUS");
					OnGainFocus();
					//s_pSelf->OnEvent(AE_GAIN_FOCUS, NULL, NULL);	
					gameflow::GameFlowManager::Instance().SetLastGainFocus(TIMER().Time());
					m_HasFocus = true;
				} else
				{
					_LOG(MSG_WARNING, "LOST FOCUS");
					OnLooseFocus();
					m_HasFocus = false;
				}
			}
			break;

/////////////////////////////////////////////////////////////////////////
// Mouse Events
		case WM_NCMOUSEMOVE:
		case WM_NCMOUSELEAVE:
		case WM_MOUSELEAVE:
		{
			bool MouseWasInside = m_MouseInsideClient;
			m_MouseInsideClient = false;
			m_MouseTrackingSet = false;
			if (MouseWasInside)
			{
				GET_MOUSE().OnMouseLeave();
			}
		}
		break;
		case WM_MOUSEMOVE:
		{
			bool MouseWasInside = m_MouseInsideClient;
			m_MouseInsideClient = true;

			m_AbsMouseX = GET_X_LPARAM(_lparam); 
			m_AbsMouseY = GET_Y_LPARAM(_lparam); 

			math::Vec2 Pos = MapPointToPos(m_AbsMouseX, m_AbsMouseY);
			m_MouseX = Pos.x;
			m_MouseY = Pos.y;
			
			if (m_MouseX < 0 || m_MouseX > 1 || m_MouseY < 0 || m_MouseY > 1)
			{
				m_MouseInsideClient = false;
				UTIL_CLAMP(m_MouseX, 0, 1);
				UTIL_CLAMP(m_MouseY, 0, 1);
			}

			GET_MOUSE().OnMouseMove(math::Vec2(m_MouseX, m_MouseY));

			if (m_MouseInsideClient && !MouseWasInside)
			{
				GET_MOUSE().OnMouseEnter();
			}
			else if (!m_MouseInsideClient && MouseWasInside)
			{
				GET_MOUSE().OnMouseLeave();
			}

			if (m_MouseInsideClient && !m_MouseTrackingSet)
			{
				ResetMouseTracking();
			}
		} 
		break;
		case WM_LBUTTONDOWN:	GET_MOUSE().OnMousePress(input::Mouse::BUTTON_LEFT); break;
		case WM_LBUTTONUP:		GET_MOUSE().OnMouseRelease(input::Mouse::BUTTON_LEFT); break;
		case WM_RBUTTONDOWN:	GET_MOUSE().OnMousePress(input::Mouse::BUTTON_RIGHT); break;
		case WM_RBUTTONUP:		GET_MOUSE().OnMouseRelease(input::Mouse::BUTTON_RIGHT); break;
		case WM_MBUTTONDOWN:	GET_MOUSE().OnMousePress(input::Mouse::BUTTON_CENTER); break;
		case WM_MBUTTONUP:		GET_MOUSE().OnMouseRelease(input::Mouse::BUTTON_CENTER); break;
		case WM_MOUSEWHEEL:		
								GET_MOUSE().OnMouseWheel((short)(HIWORD(_wparam))); break;
/////////////////////////////////////////////////////////////////////////
// KB Events
		case WM_CHAR:
		if (HasFocus())				
		{
			GET_KEYBOARD().OnCharReceived((UINT)_wparam);
		}
		break;
		case WM_KEYDOWN:	// same
		if (HasFocus())
		{
			MSG	msg;
			msg.hwnd = _hwnd;
			msg.lParam = _lparam;
			msg.wParam = _wparam;
			msg.message = _msg;
			// no info for the rest?
			TranslateMessage(&msg);	// need to process it to get WM_CHAR
			input::Keyboard::Instance().OnCharPressed((unsigned int)_wparam);
		}
		break;
		case WM_KEYUP:
		if (HasFocus())
		{
			input::Keyboard::Instance().OnCharReleased((unsigned int)_wparam);
		} break;
		case WM_DEADCHAR:			break;
		case WM_SYSCOMMAND:			break;
		case WM_SYSKEYUP:
			if (_wparam == VK_F10)
			{
				if (HasFocus())
				{
					input::Keyboard::Instance().OnCharReleased((unsigned int)_wparam);
				}
			}
			break;
		case WM_SYSKEYDOWN:
			if (_wparam == 18 && _lparam & (1<<29))	// trap and deal with alt
				return false;
			if (_wparam == VK_F10)
			{
				// F10 registers as a menu-key under windows.
				// should probably unify this; ugly cut-n-paste code
				if (HasFocus())
				{
					MSG	msg;
					msg.hwnd = _hwnd;
					msg.lParam = _lparam;
					msg.wParam = _wparam;
					msg.message = _msg;
					// no info for the rest?
					TranslateMessage(&msg);	// need to process it to get WM_CHAR
					input::Keyboard::Instance().OnCharPressed((unsigned int)_wparam);
					return 0;
				}

			}
		break;
/////////////////////////////////////////////////////////////////////////
// Random Junk. Ignore if not appropriate
		case WM_DROPFILES:	
			{
				HDROP query = (HDROP) _wparam;
				int count = DragQueryFile( query, 0xFFFFFFFF, 0, 0 );
				for (int i=0; i<count; i++)
				{
					char		file[512];
					DragQueryFile(query, i, file, 512);
					OnFileDrag(file);
				}
			}
			break;
	}
	// Let the default window procedure handle 
	// any message that we don't care about
	return ::DefWindowProc ( _hwnd, _msg, _wparam, _lparam );
}

LRESULT CALLBACK WindowHandlerWin32::defWndProc( HWND _hwnd, UINT _msg, WPARAM _wparam, LPARAM _lparam )
{
	if (pSelf)
	{
		return pSelf->WndProc(_hwnd, _msg, _wparam, _lparam);
	}
	// Let the default window procedure handle 
	// any message that we don't care about
	return ::DefWindowProc ( _hwnd, _msg, _wparam, _lparam );
}

void WindowHandlerWin32::ResetMouseTracking()
{
	if (m_MouseTrackingSet) return;

	TRACKMOUSEEVENT tme;
	memset(&tme, 0, sizeof(TRACKMOUSEEVENT));

	tme.cbSize = sizeof(TRACKMOUSEEVENT);
	tme.dwFlags = TME_LEAVE;
	tme.hwndTrack = m_hwnd;
	tme.dwHoverTime = HOVER_DEFAULT;

	m_MouseTrackingSet = (TRUE == ::_TrackMouseEvent(&tme));
}

#endif //_PLATFORM_WIN32
